"""
人脸识别Service层
遵循开发规范，实现业务逻辑，禁止导入ORM模型
"""
import uuid
from typing import List, Optional, Tuple, Union
from datetime import datetime
import numpy as np

from models.business_models import (
    FaceDto, FaceDetectDto, FaceCompareDto,
    FaceSearchResultDto
)
from models.database_models import FaceModel
from repositories.database_factory import database_factory
from services.face_engine import face_engine
from utils.faiss_index import faiss_manager
from utils.image_utils import ImageUtils
from utils.logger import app_logger
from config.settings import settings


class FaceService:
    """人脸识别业务逻辑服务"""

    def __init__(self):
        self.face_repo = database_factory.get_face_repository()
        self.face_engine = face_engine
        self.faiss_manager = faiss_manager
        self.match_threshold = settings.face_match_threshold

    # ==================== 人脸添加 ====================

    def add_face(
        self,
        person_id: str,
        person_name: str,
        image_base64: str,
        meta_info: Optional[dict] = None
    ) -> Tuple[bool, Union[FaceDto, str]]:
        """
        添加人脸

        Args:
            person_id: 人员ID
            person_name: 人员姓名
            image_base64: 图片base64
            meta_info: 扩展信息

        Returns:
            (成功标志, FaceDto或错误信息)
        """
        try:
            # 1. 解码图片
            img = ImageUtils.base64_to_cv2(image_base64)
            if img is None:
                error_msg = "图片解码失败"
                app_logger.error(error_msg)
                return False, error_msg

            # 2. 验证图片质量
            # is_valid, error_msg = ImageUtils.validate_image(img, settings.min_face_size)
            # if not is_valid:
            #     app_logger.error(f"图片质量验证失败: {error_msg}")
            #     return False, error_msg

            # 3. 验证人脸质量
            is_valid, error_msg = self.face_engine.validate_face_quality(img)
            if not is_valid:
                app_logger.error(f"人脸质量验证失败: {error_msg}")
                return False, error_msg

            # 4. 提取特征
            feature_dto = self.face_engine.extract_feature(img)
            if not feature_dto:
                error_msg = "人脸特征提取失败"
                app_logger.error(error_msg)
                return False, error_msg

            # 5. 生成face_id
            face_id = f"face_{uuid.uuid4().hex[:16]}"

            # 6. 保存到数据库
            face_model = FaceModel(
                face_id=face_id,
                person_id=person_id,
                person_name=person_name,
                feature_vector=feature_dto.feature_vector,
                quality_score=feature_dto.quality,
                face_rect=feature_dto.face_rect,
                meta_info=meta_info,
                is_active=True
            )

            self.face_repo.add_face(face_model)

            # 7. 添加到FAISS索引
            self.faiss_manager.add_vector(face_id, feature_dto.feature_vector)
            self.faiss_manager.save()

            # 8. 转换为DTO返回
            face_dto = FaceDto(
                face_id=face_id,
                person_id=person_id,
                person_name=person_name,
                quality_score=feature_dto.quality,
                face_rect=feature_dto.face_rect,
                is_active=True,
                created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                meta_info=meta_info
            )

            app_logger.info(f"人脸添加成功: face_id={face_id}, person_id={person_id}")
            return True, face_dto

        except Exception as e:
            error_msg = f"添加人脸失败: {str(e)}"
            app_logger.error(error_msg, exc_info=True)
            return False, error_msg

    # ==================== 人脸比对 ====================

    def compare_faces(
        self,
        image_a_base64: str,
        image_b_base64: str
    ) -> Optional[FaceCompareDto]:
        """
        比对两张人脸

        Args:
            image_a_base64: 图片A的base64
            image_b_base64: 图片B的base64

        Returns:
            比对结果DTO
        """
        try:
            # 1. 解码图片
            img_a = ImageUtils.base64_to_cv2(image_a_base64)
            img_b = ImageUtils.base64_to_cv2(image_b_base64)

            if img_a is None or img_b is None:
                app_logger.error("图片解码失败")
                return None

            # 2. 提取特征
            feature_a = self.face_engine.extract_feature(img_a)
            feature_b = self.face_engine.extract_feature(img_b)

            if not feature_a or not feature_b:
                app_logger.error("人脸特征提取失败")
                return None

            # 3. 计算相似度
            similarity = self.face_engine.compare_features(
                feature_a.feature_vector,
                feature_b.feature_vector
            )

            # 4. 判断是否匹配
            is_match = similarity >= self.match_threshold

            result = FaceCompareDto(
                similarity=similarity,
                is_match=is_match,
                threshold=self.match_threshold
            )

            app_logger.info(f"人脸比对完成: similarity={similarity:.4f}, is_match={is_match}")
            return result

        except Exception as e:
            app_logger.error(f"人脸比对失败: {e}", exc_info=True)
            return None

    # ==================== 人脸识别 ====================

    def search_face(
        self,
        image_base64: str,
        top_k: int = 5,
        threshold: float = None
    ) -> List[FaceSearchResultDto]:
        """
        在人脸库中识别人脸

        Args:
            image_base64: 待识别图片base64
            top_k: 返回前K个结果
            threshold: 相似度阈值（不传则使用配置值）

        Returns:
            识别结果列表
        """
        try:
            if threshold is None:
                threshold = self.match_threshold

            # 1. 解码图片
            img = ImageUtils.base64_to_cv2(image_base64)
            if img is None:
                app_logger.error("图片解码失败")
                return []

            # 2. 提取特征
            feature_dto = self.face_engine.extract_feature(img)
            if not feature_dto:
                app_logger.error("人脸特征提取失败")
                return []

            # 3. FAISS检索
            search_results = self.faiss_manager.search(
                feature_dto.feature_vector,
                top_k=top_k
            )

            if not search_results:
                app_logger.info("未找到匹配的人脸")
                return []

            # 4. 过滤并转换结果
            results = []
            for face_id, similarity in search_results:
                if similarity >= threshold:
                    # 从数据库获取详细信息
                    face_model = self.face_repo.get_face_by_face_id(face_id)
                    if face_model and face_model.is_active:
                        result_dto = FaceSearchResultDto(
                            face_id=face_id,
                            person_id=face_model.person_id,
                            person_name=face_model.person_name,
                            similarity=similarity
                        )
                        results.append(result_dto)

            app_logger.info(f"人脸识别完成: 找到{len(results)}个匹配结果")
            return results

        except Exception as e:
            app_logger.error(f"人脸识别失败: {e}", exc_info=True)
            return []

    # ==================== 人脸检测 ====================

    def detect_faces(self, image_base64: str) -> List[FaceDetectDto]:
        """
        检测图片中的人脸

        Args:
            image_base64: 图片base64

        Returns:
            人脸检测结果列表
        """
        try:
            # 1. 解码图片
            img = ImageUtils.base64_to_cv2(image_base64)
            if img is None:
                app_logger.error("图片解码失败")
                return []

            # 2. 检测人脸
            results = self.face_engine.detect_faces(img)

            app_logger.info(f"人脸检测完成: 检测到{len(results)}张人脸")
            return results

        except Exception as e:
            app_logger.error(f"人脸检测失败: {e}", exc_info=True)
            return []

    # ==================== 人脸删除 ====================

    def delete_face(self, face_id: str) -> bool:
        """
        删除人脸

        Args:
            face_id: 人脸ID

        Returns:
            是否成功
        """
        try:
            # 1. 数据库逻辑删除
            success = self.face_repo.delete_face_by_face_id(face_id)

            if success:
                # 2. 从FAISS索引删除
                self.faiss_manager.remove_by_face_id(face_id)
                self.faiss_manager.save()

                app_logger.info(f"人脸删除成功: face_id={face_id}")
                return True
            else:
                app_logger.warning(f"人脸不存在: face_id={face_id}")
                return False

        except Exception as e:
            app_logger.error(f"删除人脸失败: {e}", exc_info=True)
            return False

    # ==================== 工具方法 ====================

    def get_face_info(self, face_id: str, include_deleted: bool = False) -> Optional[FaceDto]:
        """
        获取人脸信息
        
        Args:
            face_id: 人脸ID
            include_deleted: 是否包含已删除的记录（默认False）
        
        Returns:
            人脸DTO，未找到返回None
        """
        try:
            face_model = self.face_repo.get_face_by_face_id(face_id, include_deleted=include_deleted)
            if not face_model:
                return None

            return FaceDto(
                face_id=face_model.face_id,
                person_id=face_model.person_id,
                person_name=face_model.person_name,
                quality_score=face_model.quality_score,
                face_rect=face_model.face_rect,
                is_active=face_model.is_active,
                created_at=face_model.created_at.strftime("%Y-%m-%d %H:%M:%S") if face_model.created_at else None,
                meta_info=face_model.meta_info
            )

        except Exception as e:
            app_logger.error(f"获取人脸信息失败: {e}", exc_info=True)
            return None

    def rebuild_index(self) -> bool:
        """重建FAISS索引"""
        try:
            app_logger.info("开始重建FAISS索引...")

            # 从数据库获取所有人脸特征
            face_features = self.face_repo.get_all_face_features(only_active=True)

            # 重建索引
            self.faiss_manager.rebuild_from_database(face_features)

            app_logger.info(f"FAISS索引重建成功: {len(face_features)}条记录")
            return True

        except Exception as e:
            app_logger.error(f"重建索引失败: {e}", exc_info=True)
            return False

    def get_statistics(self) -> dict:
        """获取统计信息"""
        try:
            total_faces = self.face_repo.count_faces(only_active=True)
            index_count = self.faiss_manager.get_total_count()

            return {
                "total_faces": total_faces,
                "index_count": index_count,
                "is_synced": total_faces == index_count
            }

        except Exception as e:
            app_logger.error(f"获取统计信息失败: {e}", exc_info=True)
            return {}
